package com.EmailShell.EmailShell;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.speech.RecognizerIntent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;

import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class EmailShellActivity extends Activity implements OnInitListener {
	
	private static final int REQUEST_CODE = 1234;
	// for email context differentiation
	private static final int INVALID = 0;
	private static final int INBOX = 1;
	private static final int COMPOSE = 2;
	private static final int MESSAGE = 3;
	private static final int GLOBAL = 4;
	
	// handle invalid attempts
	private int INVALID_COMMAND = 0;
	private int INVALID_ATTEMPS = 3;
	
    private ListView wordsList;
    private String droid_command;
	//TTS object
	private TextToSpeech myTTS;
	//status check code
	private int MY_DATA_CHECK_CODE = 0;
	public int CURRENT_EMAIL_VIEW = 0;
	// Object that handles and verifies commands uttered by the user
	private Commands commandList = new Commands();
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button inboxButton = (Button) findViewById(R.id.inboxButton);
        
        wordsList = (ListView) findViewById(R.id.list);
        
        //check for TTS data
        Intent checkTTSIntent = new Intent();
        checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
        
        // Disable button if no recognition service is present
        PackageManager pm = getPackageManager();
        List<ResolveInfo> activities = pm.queryIntentActivities(
                new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
        if (activities.size() == 0)
        {         
            inboxButton.setEnabled(false);
            inboxButton.setText("Recognizer not present");
        }
    }
   
	/**
	 * Set up Text to speech engine
	 */
	public void onInit(int initStatus) {
	
		//check for successful instantiation
		if (initStatus == TextToSpeech.SUCCESS) {
			if(myTTS.isLanguageAvailable(Locale.US)==TextToSpeech.LANG_AVAILABLE)
				myTTS.setLanguage(Locale.US);
		}
		else if (initStatus == TextToSpeech.ERROR) {
			Toast.makeText(this, "Sorry! Text To Speech failed...", Toast.LENGTH_LONG).show();
		}
	}
    
	/**
     * Fire an intent to start the voice recognition activity.
     */
    private void startVoiceRecognitionActivity()
    {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Voice recognition Demo...");
        startActivityForResult(intent, REQUEST_CODE);
    }
	   
    /**
     * Handle the action of the button being clicked
     */
    public void inboxButtonClicked(View v)
    {
    	CURRENT_EMAIL_VIEW = GLOBAL;
        droid_command = "Welcome to the Email Shell Application.";
        speakWords(droid_command);
    }
 
    /**
     * Invoke TTS to utter the text stored in 'speech'.
     * Calculate the length of time needed to pause the system before invoking
     * the voice recognition activity. This is to ensure that the voice recognition activity 
     * does not pick up the sound generated by the TTS engine.
     * @param speech
     */
    private void speakWords(String speech) {
    	//speak straight away
    	myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
    	
    	// Determine the length of time to pause the system before starting the voice recognition    	
    	int pauseLength = speech.length() * 50;
    	if (speech.contains(".")) {
    		pauseLength += 1000;
    	}
    	
    	Handler handler = new Handler(); 
        handler.postDelayed(new Runnable() { 
             public void run() { 
            	// Start the voice recognition activity to receive command from user
                 startVoiceRecognitionActivity(); 
             } 
        }, pauseLength);
	}

    private void speak(String speech) {
    	//speak straight away
    	myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
    }
    /**
     * Handle the results from the voice recognition activity and TTS engine
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == MY_DATA_CHECK_CODE) {
			if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
			//the user has the necessary data - create the TTS
				myTTS = new TextToSpeech(this, this);
			}
			else {
				//no data - install it now
				Intent installTTSIntent = new Intent();
				installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
				startActivity(installTTSIntent);
			}
		}
        
        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK)
        {
            // Populate the wordsList with the String values the recognition engine thought it heard
            ArrayList<String> matches = data.getStringArrayListExtra(
                    RecognizerIntent.EXTRA_RESULTS);
            wordsList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                    matches));            
            
            int result = commandList.verifyCommand(matches, CURRENT_EMAIL_VIEW);
            handleCommand(result, CURRENT_EMAIL_VIEW);
            
        }
        
        super.onActivityResult(requestCode, resultCode, data);
    }
    

	private void handleCommand(int state, int emailContextView) {
		if ( state == INVALID ) {
        	handleInvalidCmd(emailContextView);
        }
		else if (state == INBOX) {
			handleInboxCmd(commandList.getUsrCommand());
		}
		else if (state == MESSAGE) {
			handleMessageCmd(commandList.getUsrCommand());
		}
		else if (state == COMPOSE) {
			handleComposeCmd(commandList.getUsrCommand());
		}
		else if (state == GLOBAL) {
			handleGlobalCmd(commandList.getUsrCommand());
		}
    }
	
	private void handleInvalidCmd(int emailContextView) {
		// count the number of invalid attempts
    	INVALID_COMMAND += 1;
    	// if the number of attempts exceed do not 3 attempts, have the user try again
    	if (INVALID_COMMAND < INVALID_ATTEMPS) {
    		droid_command = "That is not a valid command. Please say a command " + Integer.toString(INVALID_COMMAND);
    		speakWords(droid_command);
    	}
    	// attempts by the user have exceed 3 tries. Assume the user does not know which commands are valid
    	else {
    		// reset the number of invalid attempts back to zero
    		INVALID_COMMAND = 0;
    		// determine which view is active
    		if (emailContextView == GLOBAL) {
    			droid_command = "The following is a list of valid commands in the global view:";
        		//return a list of possible commands in global view
        		for (int i = 0; i < commandList.masterCmdList.size(); i++) {
        			droid_command += commandList.masterCmdList.get(i) + " ";
        		}
        		speakWords(droid_command + ".");
    		}
    		else if (emailContextView == INBOX) {
    			droid_command = "The following is a list of valid commands in the inbox view:";
        		//return a list of possible commands in inbox view
        		for (int i = 0; i < commandList.inboxCmdList.size(); i++) {
        			droid_command += commandList.inboxCmdList.get(i) + " ";
        		}
        		speakWords(droid_command + ".");
    		} 
    		else if (emailContextView == MESSAGE) {
    			droid_command = "The following is a list of valid commands in the message view:";
        		//return a list of possible commands in message view
        		for (int i = 0; i < commandList.messageCmdList.size(); i++) {
        			droid_command += commandList.messageCmdList.get(i) + " ";
        		}
        		speakWords(droid_command + ".");
    		} 
    		else if (emailContextView == COMPOSE) {
    			droid_command = "The following is a list of valid commands in the compose view:";
        		//return a list of possible commands in compose view
        		for (int i = 0; i < commandList.composeCmdList.size(); i++) {
        			droid_command += commandList.composeCmdList.get(i) + " ";
        		}
        		speakWords(droid_command + ".");
    		}
    		else {
    			droid_command = "Droid does not recognize that command.";
    			speakWords(droid_command);
    		}
    	}
	}
	
	private void handleGlobalCmd(String usrCmd) {
		if (usrCmd == "email") {
			speak("You said: email.");
			openInbox();
		}
		else if (usrCmd == "inbox") {
			speak("You said: inbox.");
			openInbox();
		}
		else if (usrCmd == "exit") {
			speak("You said: exit.");
			finish();
		}
		else if (usrCmd == "quit") {
			speak("You said: quit.");
			finish();
		}
		else if (usrCmd == "home") {
			speak("You said: home.");
		}
		else {
			speak("Droid does not recognize global level command.");
		}
	}
	
	private void handleInboxCmd(String usrCmd) {
		if (usrCmd == "read") {
			speak("You said: read.");
		}
		else if (usrCmd == "reply") {
			speak("You said: reply.");
		}
		else if (usrCmd == "reply all") {
			speak("You said: reply all.");
		}
		else if (usrCmd == "forward") {
			speak("You said: forward.");
		}
		else if (usrCmd == "delete") {
			speak("You said: delete.");
		}
		else if (usrCmd == "message") {
			speak("You said: message.");
		}
		else {
			speak("Droid does not recognize inbox level command.");
		}
	}
	
	private void handleMessageCmd(String usrCmd) {
		if (usrCmd == "reply") {
			speak("You said: reply.");
		}
		else if (usrCmd == "reply all") {
			speak("You said: reply all.");
		}
		else if (usrCmd == "forward") {
			speak("You said: forward.");
		}
		else if (usrCmd == "delete") {
			speak("You said: delete.");
		}
		else if (usrCmd == "subject") {
			speak("You said: subject.");
		}
		else if (usrCmd == "sender") {
			speak("You said: sender.");
		}
		else if (usrCmd == "message") {
			speak("You said: message.");
		}
		else if (usrCmd == "recipients") {
			speak("You said: recipient.");
		}
		else if (usrCmd == "body") {
			speak("You said: body.");
		}
		else if (usrCmd == "back") {
			speak("You said: back.");
		}
		else if (usrCmd == "return") {
			speak("You said: return.");
		}
		else {
			speak("Droid does not recognize message level command.");
		}
		
	}
	
	private void handleComposeCmd(String usrCmd) {
		if (usrCmd == "send") {
			speak("You said: send.");
		}
		else if (usrCmd == "save") {
			speak("You said: save.");
		}
		else if (usrCmd == "delete") {
			speak("You said: delete.");
		}
		else if (usrCmd == "subject") {
			speak("You said: subject.");
		}
		else if (usrCmd == "message") {
			speak("You said: message.");
		}
		else if (usrCmd == "recipient") {
			speak("You said: recipient.");
		}
		else if (usrCmd == "back") {
			speak("You said: back.");
		}
		else if (usrCmd == "return") {
			speak("You said: return.");
		}
		else if (usrCmd == "record") {
			speak("You said: record.");
		}
		else {
			speak("Droid does not recognize compose level command.");
		}
		
	}
	
	private void openInbox () {
		Intent myIntent = new Intent();
		myIntent.setClass(findViewById(R.id.inboxButton).getContext(), InboxActivity.class);
		startActivity(myIntent);
	}
}